/**
 * 组件中的方法
 */

import { isFunciton, isObject, ShapeFlags } from "@vue/shared";
import { PublicInstanceProxyHandlers } from "./componentPubliceInstance";

export function createComponentInstance(vnode) {
  const instance = { // 组件实例
    vnode,
    type: vnode.type, // 组件对象或者元素的字符串
    props: {}, // 组件里注册的属性
    attrs: {}, // attrs 排除组件里没有注册的属性
    slots: {},
    ctx: {},
    data: {},
    render: null,
    setupState: {}, // 如果 setup 返回对象作为 setupState
    isMounted: false, // 标识组件是否挂载
  }

  instance.ctx = {
    _: instance
  };

  return instance;
}

export function setupComponent(instance) {
  const { props, children } = instance.vnode;
  instance.props = props; // initProps()
  instance.children = children; // 包含插槽解析 initSlot()

  // 判断是否事有状态组件，函数组件

  let isStateful = instance.vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT;
  if (isStateful) { // 有状态组件
    // 调用当前实例的 setup 方法，用 setup 的返回值赋值给 setupState 和对应的 render 方法
    setupStatefulComponent(instance);
  }
}


function createSetupContext(instance) {
  return {
    attrs: instance.attrs,
    slots: instance.slots,
    emit: () => {},
    expose: () => {}
  }
}

function finishComponentSetup(instance) {
  const Component = instance.type;

  if (!instance.render) {
    // 对 template 模板进行编译，生成 render 函数
    if (!Component.render && Component.template) {
      // 编译，将编译的结果赋值给 Component.render
    }
    instance.render = Component.render;
  }
  // Vue3 这里就是对 Vue2 的 API 做兼容的 applyOptions
}
function handleSetupResult(instance, setupResult) {
  
  if (isFunciton(setupResult)) { // 用户编写的 setup 返回函数
    instance.render = setupResult;
  } else if (isObject(setupResult)) { // 用户编写的 setup 返回对象
    instance.setupState = setupResult;
  }

  finishComponentSetup(instance);
}

export let currentInstance = null;

export let setCurrentInstace = instance => {
  currentInstance = instance;
}
// 返回 “当前组件” 的实例
export let getCurrentInstace = () => {
  return currentInstance;
}

function setupStatefulComponent(instance) {
  // 1. 代理，传递给 render 函数的参数
  instance.proxy = new Proxy(instance.ctx, PublicInstanceProxyHandlers as any);
  // 2. 获取组件的类型，获取组件的 setup 方法
  const Component = instance.type;

  const { setup } = Component;

  // 判断用户是否书写的 setup
  if (setup) {

    currentInstance = instance;

    const setupState = createSetupContext(instance);
    // 调用用户组件中的 setup 函数
    const setupResult = setup(instance.props, setupState);


    currentInstance = null;

    handleSetupResult(instance, setupResult);
    
  } else {
    // 进行组件的初始化
    finishComponentSetup(instance);
  }

  // 3. 调用用户编写的 render 进行挂载渲染到页面
  // Component.render && Component.render(instance.proxy);
}
